/*=============================================================================
Para compilar:
	gcc montecarlo_sequencial.c -o montecarlo_sequencial -lm -lgmp

Para isso, é necessário ter instalado a biblioteca GMP: http://gmplib.org/
=============================================================================*/

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>
#include <gmp.h>

/* Outras constantes */
#define NUMERO_PONTOS 1000000000

/* 10.000.000 de dígitos, em bits */
/* #define bits_precisao ceil(10000000.0 * log2(10)) */
#define bits_precisao 33219281

/* Calcula o raio, que é a distância do ponto gerado para a origem */
double raio(double x, double y)
{
    return sqrt(x * x + y * y);
}


/* Função para calcular o tempo de execução */
double tempo()
{
    struct timeval tv;
    gettimeofday(&tv,0);
    return tv.tv_sec + tv.tv_usec/1e6;
}



int main(void)
{
    /* Variáveis para registrar o tempo */
    double inicio, fim;

    /* Arquivo de saída */
    FILE *output;

    /* Coordenadas X e Y*/
    double x, y;

    /* Variáveis para contar o número de iterações e o número de vezes que o ponto gerado estava dentro do círculo*/
    unsigned long int tentativas = 0, acertos = 0;

    /* Variável para realizar um loop antes de verificar o erro (custoso)*/
    unsigned int loop;

    /* Variáveis para armazenar o valor calculado e o valor real de pi, na biblioteca GMP */
    mpf_t Pi;
    
    /* Inicializa as variáveis da biblioteca GMP */
    mpf_init2(Pi, bits_precisao);

    /* Semeia os números aleatórios com o tempo da execução */
    srand48(time(NULL));

    /* Registra o tempo inicial */
    inicio = tempo();

    /* Há a necessidade de limitar o número de iterações, pois essa precisão em monte carlo demoraria vários anos */
    for(loop = 0; loop < NUMERO_PONTOS; loop++){

	   /* Sorteia-se coordenadas x e y, variando de 0 a 1*/
	   x = drand48();
	   y = drand48();
		
	   /* Verifica se esses pontos estão dentro de um círculo de raio 1*/
	   if(raio(x,y) <= (double) 1.0) 
	   {
	          /* Se estiver, contabiliza o acerto*/
		  acertos++;
	   }

	   /* Contabiliza o número de pontos */
	   tentativas++;
    }

    /* Calcula pi na biblioteca GMP*/
    mpf_set_ui(Pi, acertos);
    mpf_div_ui(Pi, Pi, tentativas);
    mpf_mul_ui(Pi, Pi, 4);

     
    /* Registra o tempo final */
    fim = tempo();

    /* Abre o arquivo de saída */
    output = fopen("montecarlo_sequencial.txt", "a+");

    /* Atendida a precisão ou o limite de iterações, imprime os resultados */
    printf("Monte Carlo Sequencial executado com sucesso\n");

	fprintf(output, "\n--------------------------------------------------------\n");
	fprintf(output, " Monte Carlo Sequencial executado com sucesso.\n");
	fprintf(output, " Os primeiros 30 digitos do resultado sao : ");
	mpf_out_str(output, 10, 30, Pi);
	fprintf(output, "\n O tempo gasto com a execucao foi de %lf segundos.\n", (fim - inicio));
	fprintf(output, " O numero de iteracoes necessarias foi %ld.\n", tentativas);



    /* Fecha o ponteiro do arquivo */
    fclose(output);

    /* Desaloca as variáveis usadas */
    mpf_clear(Pi);
 
    return 0;
}
